// 2. 类&对象
/**
 * 1. 类定义 (class关键字、修饰符、成员变量、成员方法)
 * 2. 访问成员
 * 3. 类成员函数（定义、inline、使用、范围解析符号::、点运算符.）
 * 4. 类访问修饰符
 *        public    公有成员在类外部可以直接访问
 *        private   私有成员在类外部不可访问，只有类和友元函数可以访问；不使用修饰符时，默认是private类
 *        protected 受保护成员跟私有成员类似，有一点不同是派生类（即子类）中，是可以访问的
 * 5. 类继承 
 *     语法     class ChildClassName : (type) FatherClassName
 *     继承方式
 *        #51   public继承     
 *        #52   private继承
 *        #53   protected继承
 *        总结： 
 *              基类public成员，子类可访问，public继承变为公有类型，private继承变成私有类型，protected继承变成受保护类型
 *              基类private成员，子类不可访问，public继承变成私有类型，private继承变成私有类型，protected继承变成私有类型
 *              基类protected成员，子类中可以访问，public继承变成受保护类型，private继承变成私有类型，protected继承变成受保护类型
 * 6. 构造函数
 *        语法：   className::className()
 *        定义、使用
 *        带参数的构造函数
 *        多个重载
 *        初始化列表初始化字段 className::className(type a,type b,type c):A(a),B(b),C(c)
 * 7. 析构函数
 *        语法:     ~className()
 *        定义、使用
 *        只能声明一个
 * 8. 拷贝构造函数
 *        语法：    className::className(const className &obj)
 *        定义、使用 没有定义的话，编译器会自习创建一个。如果类中有指针变量，那必须要有一个拷贝构造函数。
 *        使用场景
 *                #81  函数传值调用（无拷贝构造函数时，已终止，退出代码: 3221226356）
 *                #82  用一个已有的同类型对象来初始化新创建的对象
 *                函数直接返回 ;写法 classname xxx = obj; 或者 classname xxx(obj); （无拷贝构造函数时，已终止，退出代码: 3221226356）
 *                #83  函数直接返回对象 （编译器进行了优化,关闭优化加上-fno-elide-constructors）
 * 9. 友元函数
 *        作用： 可以访问所有私有成员和受保护成员。友元函数没有this指针。
 *        友元函数 friend fun(classname obj);声明了某个类classname有友元函数，该函数可以通过传入对象，在函数内直接使用对象上的私有成员和受保护成员
 *        友元类   friend class classname;声明了某个类X1有友元类 classname,在这个classname类中，可以使用传入的类X1对象的私有成员和受保护成员
 * 10. 内联函数
 *        定义方式: 类内部定义、使用inline说明符
 *        使用场景：短代码（1~3行）、非递归
 * 11. c++中的this指针
 *        每个对象都可以通过this指针访问自己的地址，友元函数不是类的成员，友元函数没有this指针
 * 12. 指向类的指针(成员访问运算符->访问指针所指向的类的成员)
 * 13. 静态成员
 *        静态成员变量
 *            不可在类内部初始化，一定要初始化的化可以通过范围解析运算符::来重新声明静态变量从而对它初始化；语法：type classname::variale = xx;
 *            所有对象共享，私有变量的话，可以通过公有静态成员方法访问
 *        静态成员函数
 * 
 * 扩展
 * 1. 初始化列表参数顺序问题
 * 2. new动态开辟内存空间
*/

#include <iostream>
#define __mark 83

/**
 * #51 public继承
*/
#if __mark == 51
class Test
{
private:
  int a;

public:
  int a1 = 1;
  Test(/* args */);
  ~Test();

private:
  int a2 = 2;

protected:
  int a3 = 3;
};

class MinTest : public Test
{
private:
  int a = 0;

public:
  MinTest(/* args */);
  ~MinTest();
  void print()
  {

    std::cout << "a : " << a << std::endl;   // 私有成员，类中可以访问
    std::cout << "a1 : " << a1 << std::endl; // 基类公有成员，可以在子类中使用
    // std::cout << "a2 : " << a2 << std::endl; // 基类私有成员，不可再子类中使用
    std::cout << "a3 : " << a3 << std::endl; // 基类中受保护成员，可以在子类中使用
  }

private:
protected:
};

MinTest::MinTest(/* args */)
{
}

MinTest::~MinTest()
{
}

Test::Test(/* args */)
{
}

Test::~Test()
{
}

int main(void)
{
  MinTest mt1;
  // std::cout << "a : " << mt1.a << std::endl; // 私有成员，类外不可访问
  std::cout << "a1 : " << mt1.a1 << std::endl; // 基类公有成员，public继承后变成公有成员，公有成员可以在类外访问
  // std::cout << "a2 : " << mt1.a2 << std::endl;// 基类中私有成员，public继承后变成私有成员，类外不可访问
  // std::cout << "a3 : " << mt1.a3 << std::endl; // 基类中受保护成员，public继承后变成受保护成员，类外不可直接访问
  printf("----------------end----------------\n");
  // system("pause");
  return 0;
}

/**
 * #52 private私有继承
*/
#elif __mark == 52
class Test
{
private:
  int a;

public:
  int a1 = 1;
  Test(/* args */);
  ~Test();

private:
  int a2 = 2;

protected:
  int a3 = 3;
};

class MinTest : private Test
{
private:
  int a = 0;

public:
  MinTest(/* args */);
  ~MinTest();
  void print()
  {

    std::cout << "a : " << a << std::endl;   // 私有成员，可以在类中访问
    std::cout << "a1 : " << a1 << std::endl; // 基类公有成员，可以在子类中使用
    // std::cout << "a2 : " << a2 << std::endl;// 基类私有成员，不可在子类中访问
    std::cout << "a3 : " << a3 << std::endl; // 基类受保护成员，可以在子类中访问
  }

private:
protected:
};

MinTest::MinTest(/* args */)
{
}

MinTest::~MinTest()
{
}

Test::Test(/* args */)
{
}

Test::~Test()
{
}

int main(void)
{
  MinTest mt1;
  // std::cout << "a : " << mt1.a << std::endl;// 私有成员 不可在类外部访问
  // std::cout << "a1 : " << mt1.a1 << std::endl; // 基类公有成员，private继承后变成私有成员，不可在类外部使用
  // std::cout << "a2 : " << mt1.a2 << std::endl;// 基类私有成员，private继承后变成私有成员，不可在类外部使用
  // std::cout << "a3 : " << mt1.a3 << std::endl;// 基类受保护成员，private继承后变成私有成员，不可在类外部使用
  printf("----------------end----------------\n");
  // system("pause");
  return 0;
}

/**
 * #53 protected继承
*/
#elif __mark == 53
class Test
{
private:
  int a;

public:
  int a1 = 1;
  Test(/* args */);
  ~Test();

private:
  int a2 = 2;

protected:
  int a3 = 3;
};

class MinTest : protected Test
{
private:
  int a = 0;

public:
  MinTest(/* args */);
  ~MinTest();
  void print()
  {

    std::cout << "a : " << a << std::endl;   // 私有成员 类中可以访问
    std::cout << "a1 : " << a1 << std::endl; // 公有成员，子类中可以访问；
    // std::cout << "a2 : " << a2 << std::endl;// 私有成员，子类中不可访问；
    std::cout << "a3 : " << a3 << std::endl; // 受保护成员，子类中可以使用；
  }

private:
protected:
};

MinTest::MinTest(/* args */)
{
}

MinTest::~MinTest()
{
}

Test::Test(/* args */)
{
}

Test::~Test()
{
}

int main(void)
{
  MinTest mt1;
  // std::cout << "a : " << mt1.a << std::endl; // 类私有成员，类外部不可访问
  // std::cout << "a1 : " << mt1.a1 << std::endl;// 基类公有成员，protected继承后变成受保护成员，类外不可访问
  // std::cout << "a2 : " << mt1.a2 << std::endl;// 基类私有成员，protected继承后变成私有成员，类外不可访问
  // std::cout << "a3 : " << mt1.a3 << std::endl;// 基类受保护成员，protected继承后变成受保护成员，类外不可访问
  printf("----------------end----------------\n");
  // system("pause");
  return 0;
}

/**
 * #81 拷贝构造函数--函数传值调用
*/
#elif __mark == 81
class Line
{
private:
  double *ptr;

public:
  Line(double);
  Line(const Line &);
  ~Line();
  double getLength();
  void setLength(double);
};

Line::Line(double len)
{
  std::cout << "调用构造函数" << std::endl;
  ptr = new double();
  *ptr = len;
}

Line::Line(const Line &obj)
{
  std::cout << "调用拷贝构造函数" << std::endl;
  ptr = new double();
  *ptr = *obj.ptr;
}

Line::~Line()
{
  std::cout << "调用析构函数" << std::endl;
  delete ptr; // 动态内存要手动释放
}

inline double Line::getLength()
{
  return *ptr;
}

inline void Line::setLength(double len)
{
  *ptr = len;
}
void printLen(Line);

int main(void)
{
  Line l1(10.5);
  // std::cout << "len : " << l1.getLength() << std::endl;
  // Line l2 = l1;
  // l1.setLength(2.5);
  // std::cout << "len : " << l2.getLength() << std::endl;
  printLen(l1);
  printf("----------------end----------------\n");
  // system("pause");
  return 0;
}

void printLen(Line obj)
{
  std::cout << "len : " << obj.getLength() << std::endl;
}

/**
 * #82 拷贝构造函数--用一个已有的同类型对象来初始化创建新对象
*/
#elif __mark == 82
class Line
{
private:
  double *ptr;

public:
  Line(double);
  Line(const Line &);
  ~Line();
  double getLength();
  void setLength(double);
};

Line::Line(double len)
{
  std::cout << "调用构造函数" << std::endl;
  ptr = new double();
  *ptr = len;
}

Line::Line(const Line &obj)
{
  std::cout << "调用拷贝构造函数" << std::endl;
  ptr = new double();
  *ptr = *obj.ptr;
}

Line::~Line()
{
  std::cout << "调用析构函数" << std::endl;
  delete ptr; // 动态内存要手动释放
}

inline double Line::getLength()
{
  return *ptr;
}

inline void Line::setLength(double len)
{
  *ptr = len;
}

int main(void)
{
  Line l1(10.5);
  std::cout << "len : " << l1.getLength() << std::endl;
  // Line l2 = l1;
  Line l2(l1);
  l1.setLength(2.5);
  std::cout << "len : " << l2.getLength() << std::endl;
  printf("----------------end----------------\n");
  // system("pause");
  return 0;
}

/**
 * #83 拷贝构造函数--函数直接返回对象
*/
#elif __mark == 83
class Line
{
private:
  double *ptr;

public:
  Line();
  Line(double);
  Line(const Line &);
  ~Line();
  double getLength();
  void setLength(double);
};

Line::Line()
{
  std::cout << "调用无参构造函数" << std::endl;
  ptr = new double();
}

Line::Line(double len)
{
  std::cout << "调用构造函数" << std::endl;
  ptr = new double();
  *ptr = len;
}

Line::Line(const Line &obj)
{
  std::cout << "调用拷贝构造函数" << std::endl;
  ptr = new double();
  *ptr = *obj.ptr;
}

Line::~Line()
{
  std::cout << "调用析构函数" << std::endl;
  delete ptr; // 动态内存要手动释放
}

inline double Line::getLength()
{
  return *ptr;
}

inline void Line::setLength(double len)
{
  *ptr = len;
}

Line createLine(double len)
{
  std::cout << "created params len: " << len << std::endl;
  // static Line l(len); // 已终止，退出代码: 3221226356
  Line l(len);
  std::cout << "created l len : " << l.getLength() << std::endl;
  return l;
}

int main(void)
{

  double len = createLine(10.5).getLength();
  std::cout << "1-len : " << len << std::endl;

  // Line l1(1.2);
  // l1  = createLine(6.5); // 这样写有问题

  // Line l1 = createLine(6.5);
  Line l1(createLine(6.5));
  
  std::cout << "2-len : " << l1.getLength() << std::endl;
  printf("----------------end----------------\n");
  // system("pause");
  return 0;
}

#elif __mark == 2
int main(void)
{

  printf("----------------end----------------\n");
  // system("pause");
  return 0;
}

#endif